from typing import TYPE_CHECKING, Self, overload

from vengine.ve_globals import VE_GroupIdPool, get_object, has_object
from vengine.ve_logger import get_logger
from vengine.ve_objects import VE_Object


class VE_Group:
    """ Base group of managing objects """
    
    def __init__(self, group_id: str) -> None:
        if group_id in VE_GroupIdPool:
            get_logger().warn(f"Creating group with same id ({group_id}) will override previous one", stack_info=True)
        
        VE_GroupIdPool[group_id] = self
        self.group_id: str = group_id
        
        self.__id: set[str] = set()
        
    def _add_by_id(self, object_id: str) -> None:
        if not has_object(object_id):
            get_logger().warn(f"Object(id={object_id}) doesn't exist")
            return
        if object_id in self.__id:
            get_logger().debug(f"Object(id={object_id}) is already in the group")
            return
        self.__id.add(object_id)
            
    @overload
    def add(self, __obj: "VE_Object") -> None: ...
    @overload
    def add(self, __object_id: str) -> None: ...
    def add(self, __arg) -> None:
        if isinstance(__arg, str):
            self._add_by_id(__arg)
        elif isinstance(__arg, VE_Object):
            self._add_by_id(__arg.object_id)
        else:
            raise TypeError(f"Expect {str | VE_Object}, got {type(__arg)}")
        
    def _remove_by_id(self, object_id: str) -> None:
        if not has_object(object_id):
            get_logger().warn(f"Object(id={object_id}) doesn't exist")
            return
        if object_id not in self.__id:
            get_logger().debug(f"Object(id={object_id}) is not in the group")
            return
        self.__id.remove(object_id)
    
    @overload
    def remove(self, __obj: "VE_Object") -> None: ...
    @overload
    def remove(self, __object_id: str) -> None: ...
    def remove(self, __arg) -> None:
        if isinstance(__arg, str):
            self._remove_by_id(__arg)
        elif isinstance(__arg, VE_Object):
            self._add_by_id(__arg.object_id)
        else:
            raise TypeError(f"Expect {str | VE_Object}, got {type(__arg)}")
    
    def __iter__(self) -> Self:
        self.__iter = self.__id.copy()
        return self
    
    def __next__(self) -> tuple[str, "VE_Object"]:
        if len(self.__iter) == 0:
            raise StopIteration
        object_id = self.__iter.pop()
        return object_id, get_object(object_id)
    
    @overload
    def __contains__(self, __obj: "VE_Object") -> bool: ...
    @overload
    def __contains__(self, __object_id: str) -> bool: ...
    def __contains__(self, __arg) -> bool:
        if isinstance(__arg, str):
            return __arg in self.__id
        if isinstance(__arg, VE_Object):
            return __arg.object_id in self.__id
        raise TypeError(f"Expect {str | VE_Object}, got {type(__arg)}")
